package com.wallace.downloadserver.filter

import com.wallace.downloadserver.myconst.DefineName
import com.wallace.downloadserver.myconst.ResponseMessage
import com.wallace.downloadserver.redis.getV
import com.wallace.downloadserver.util.myToken.TokenContent
import com.wallace.downloadserver.util.myToken.TokenUtil
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.data.redis.core.RedisTemplate
import javax.servlet.*
import javax.servlet.FilterConfig
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse

/**
 * @Description:
 * 解析token
 * @author Wallace
 * @Date 2022/2/11 9:58
 */
class ParseTokenFilter(private val redisTokenDB: RedisTemplate<String, Any>?) : Filter {

    private val log: Logger = LoggerFactory.getLogger(ParseTokenFilter::class.java)

    private val pathRegex: ArrayList<Regex> = ArrayList()

    override fun init(filterConfig: FilterConfig?) {
        val excludedPaths = filterConfig!!.getInitParameter("excludedPaths")
        excludedPaths.split(";").forEach {
            pathRegex.add(Regex(it))
        }
        log.debug("pathRegex = $pathRegex")
    }

    private fun needFilter(httpServletRequest: HttpServletRequest): Boolean {
        pathRegex.forEach {
            if (httpServletRequest.requestURI.matches(it)) {
                return false
            }
        }
        return true
    }

    override fun doFilter(request: ServletRequest?, response: ServletResponse?, chain: FilterChain?) {
        val httpRequest = request as HttpServletRequest
        val httpResponse = response as HttpServletResponse
        if (needFilter(httpRequest)) {
            val tokenContent: TokenContent?
            // 获取token
            val token = httpRequest.getHeader(DefineName.TOKEN)
            if (token == null) {
                log.debug("[${httpRequest.requestURI}]请求头未携带token")
                chain!!.doFilter(httpRequest, httpResponse)
            } else {
                tokenContent = TokenUtil.verifyToken(token)
                if (tokenContent == null) {
                    log.warn("token解析失败:$token")
                    httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, ResponseMessage.Error.TOKEN_INVALID)
                } else {
                    val redisToken = redisTokenDB!!.getV(tokenContent.id)
                    if (redisToken == null) {
                        log.warn("token不存在redis中：$token")
                        httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, ResponseMessage.Error.TOKEN_INVALID)
                    } else {
                        if (redisToken != token) {
                            log.warn("有token被篡改:{redisToken = $redisToken,token = $token}")
                            httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, ResponseMessage.Error.TOKEN_INVALID)
                        } else {
                            httpRequest.setAttribute(DefineName.TOKEN_CONTENT, tokenContent)
                            chain!!.doFilter(httpRequest, httpResponse)
                        }
                    }
                }
            }
        } else {
            chain!!.doFilter(httpRequest, httpResponse)
        }
    }
}